﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Security.Cryptography;
using System.Device.Location;

namespace RunCoachServer
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class RunCoachService : IRunCoachService
    {
        private static runcoachEntities _entities;

        public RunCoachService()
        {
            try
            {
                _entities = new runcoachEntities();
            }
            catch (Exception e)
            {
                Console.WriteLine("Konstruktor hiba: " + e.ToString());
            }
        }

        public Int32 Login(String username, String password)
        {
            using (MD5 md5Hash = MD5.Create())
            {
                password = GetMd5Hash(md5Hash, password);

                try
                {
                    users akt_user = _entities.users.FirstOrDefault(user => user.username == username && user.password == password);

                    if (akt_user != null)
                    {
                        return akt_user.id;
                    }
                    else
                    {
                        return 0;
                    }

                }
                catch(Exception e)
                {
                    Console.WriteLine("Login hiba: " + e.ToString());
                    return -1;
                }
            }
        }

        public void Logout()
        {
        }

        public Boolean RegisterUser(String username, String realname, String password)
        {
            using (MD5 md5Hash = MD5.Create())
            {
                password = GetMd5Hash(md5Hash, password);

                try
                {
                    users akt_user = _entities.users.FirstOrDefault(user => user.username == username || user.real_name == realname);

                    if (akt_user != null)
                    {
                        return false;
                    }

                    users new_user = new users();
                    new_user.username = username;
                    new_user.real_name = realname;
                    new_user.password = password;

                    _entities.users.AddObject(new_user);

                    return (_entities.SaveChanges() == 1);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Regisztracio hiba: " + e.ToString());
                    return false;
                }
            }
        }

        public Boolean changePassword(String username, String new_password, String old_password)
        {
            using (MD5 md5Hash = MD5.Create())
            {
                old_password = GetMd5Hash(md5Hash, old_password);
                new_password = GetMd5Hash(md5Hash, new_password);

                try
                {
                    users akt_user = _entities.users.FirstOrDefault(user => user.username == username && user.password == old_password);
                    Console.WriteLine(akt_user.ToString());
                    if (akt_user != null)
                    {
                        akt_user.password = new_password;
                        _entities.SaveChanges();
                        return true;
                    }
                    else
                    {
                        Console.WriteLine("Rossz felhasználónév - jelszó párost akarsz megváltoztatni!");
                        return false;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("ChangePassword hiba: " + e.ToString());
                    return false;
                }
            }
        }

        public Boolean getDataFromMobile(DateTime start_time, DateTime end_time, List<GeoCoordinate> coordinates, Dictionary<String, Int32> int_values)
        {
            //int_values -> avg_speed1, avg_speed2, distance, user_id

            String coordinateList = "";

            foreach(GeoCoordinate coordinate in coordinates)
            {
                if (coordinateList == "")
                {
                    coordinateList += coordinate.Latitude.ToString() + " " + coordinate.Longitude.ToString() + " "
                                        + coordinate.Altitude.ToString() + " ";
                }
                else
                {
                    coordinateList += "|" + coordinate.Latitude.ToString() + " " + coordinate.Longitude.ToString() + " "
                                        + coordinate.Altitude.ToString() + " ";
                }
            }

            runs myRun = new runs();
            myRun.start_time = start_time;
            myRun.end_time = end_time;
            myRun.coordinates = coordinateList;
            myRun.avg_speed = int_values["avg_speed1"];
            myRun.avg_speed2 = int_values["avg_speed2"];
            myRun.distance = int_values["distance"];
            myRun.user_id = int_values["user_id"];

            _entities.runs.AddObject(myRun);
            
            return _entities.SaveChanges() == 1;
        }

        public Runs[] getAllRunsData(Int32 user_id)
        {
            List<Runs> allRun = (_entities.runs.Select(o => new Runs()
            {
                id = o.id,
                start_time = o.start_time,
                end_time = o.end_time,
                avg_speed = o.avg_speed,
                avg_speed2 = o.avg_speed2,
                distance = o.distance,
                user_id = o.user_id
            })).ToList();

            List<Runs> myRuns = new List<Runs>();

            foreach (Runs akt_run in allRun)
            {
                if (akt_run.user_id == user_id)
                {
                    myRuns.Add(akt_run);
                }
            }

            return myRuns.ToArray();
        }

        public Boolean deleteRunData(Int32 id, Int32 user_id)
        {
            runs akt_run = _entities.runs.FirstOrDefault(run => run.id == id);

            if (akt_run != null && akt_run.user_id == user_id)
            {
                _entities.DeleteObject(akt_run);

                return _entities.SaveChanges() == 1;
            }

            return false;
        }

        public List<GeoCoordinate> getRunCoordinates(Int32 run_id, Int32 user_id)
        {
            runs akt_run = _entities.runs.FirstOrDefault(run => run.id == run_id && run.user_id == user_id);
            List<GeoCoordinate> _geoCoordinates = new List<GeoCoordinate>();

            if (akt_run != null)
            {
                String[] _coordinates = akt_run.coordinates.Split('|');

                foreach (String _coordinate in _coordinates)
                {
                    String[] _akt_coordinate = _coordinate.Split(' ');
                    _geoCoordinates.Add(new GeoCoordinate(Convert.ToDouble(_akt_coordinate[0]), 
                                                          Convert.ToDouble(_akt_coordinate[1]),
                                                          Convert.ToDouble(_akt_coordinate[2])));
                }
            }

            return _geoCoordinates;
        }

        private static string GetMd5Hash(MD5 md5Hash, string input)
        {
            // Convert the input string to a byte array and compute the hash. 
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

            // Create a new Stringbuilder to collect the bytes and create a string.
            StringBuilder sBuilder = new StringBuilder();

            // Loop through each byte of the hashed data and format each one as a hexadecimal string. 
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            // Return the hexadecimal string. 
            return sBuilder.ToString();
        }
    }
}
